import {Effect, EffectsCommandMap, EffectWithType, Model} from 'dva-core-ts';
import {Reducer} from 'redux';
import {GetShowFrequency} from '../api/album';
import {RootState} from '@/models/index';
import {
  init,
  pause,
  play,
  getCurrentTime,
  getDuration,
  stop,
  sound,
} from '@/config/sound';
export interface PlayModelState {
  id: string;
  title: string;
  soundUrl: string;
  thumbnailUrl: string;
  playState: string;
  currentTime: number;
  duration: number;
  previousId: string;
  nextId: string;
  sounds: {id: string; title: string}[];
}

export interface PlayModel extends Model {
  namespace: 'player';
  state: PlayModelState;
  reducers: {
    setState: Reducer;
  };
  effects: {
    fetchShow: Effect;
    play: Effect;
    pause: Effect;
    watcherCurrentTime: EffectWithType;
    previous: Effect;
    setCurrentTime: Effect;
    next: Effect;
  };
}

const initialState: PlayModelState = {
  id: '',
  soundUrl: '',
  thumbnailUrl: '',
  playState: 'paused',
  currentTime: 0,
  duration: 0,
  previousId: '',
  nextId: '',
  sounds: [],
  title: '',
};

const delay = (timeout: number) =>
  new Promise(resolve => setTimeout(resolve, timeout));

function* currentTime({call, put}: EffectsCommandMap) {
  while (true) {
    yield call(delay, 300);
    const soundCurrentTime = yield call(getCurrentTime);
    yield put({
      type: 'setState',
      payload: {
        currentTime: soundCurrentTime <= 0 ? 1 : soundCurrentTime,
        duration: getDuration(),
      },
    });
  }
}

const playerModel: PlayModel = {
  namespace: 'player',
  state: initialState,
  reducers: {
    setState(state, {payload}) {
      return {
        ...state,
        ...payload,
      };
    },
  },
  effects: {
    *fetchShow({payload}, {call, put, select}) {
      yield call(stop);
      const {data} = yield call(GetShowFrequency, {id: payload.id});

      yield put({
        type: 'setState',
        payload: {
          id: payload.id,
          soundUrl: data.soundUrl,
          duration: getDuration(),
        },
      });
      yield call(init, data.soundUrl);
      yield put({
        type: 'play',
      });
      const {id, title, thumbnailUrl, currentTime}: PlayModelState =
        yield select(({player}: RootState) => player);
      // saveProgram({
      //   id,
      //   title,
      //   thumbnailUrl,
      //   currentTime,
      //   duration: getDuration(),
      // });
      yield put({
        type: 'soundsHistory/add',
        payload: {
          data: {
            id,
            title,
            thumbnailUrl,
            currentTime,
            duration: getDuration(),
            rate: 0,
          },
        },
      });
    },
    *play({_}, {call, put, select}) {
      const {id}: PlayModelState = yield select(
        ({player}: RootState) => player,
      );
      yield put({
        type: 'setState',
        payload: {
          playState: 'playing',
        },
      });
      yield call(play);
      yield put({
        type: 'setState',
        payload: {
          playState: 'paused',
        },
      });
      yield put({
        type: 'soundsHistory/set',
        payload: {
          data: {
            id,
            rate: 100,
          },
        },
      });
    },
    *pause({_}, {call, put, select}) {
      yield call(pause);
      yield put({
        type: 'setState',
        payload: {
          playState: 'paused',
        },
      });
      const {id, currentTime}: PlayModelState = yield select(
        ({player}: RootState) => player,
      );
      // saveProgram({
      //   id,
      //   currentTime,
      // });
      yield put({
        type: 'soundsHistory/set',
        payload: {
          data: {
            id,
            currentTime,
            duration: getDuration(),
          },
        },
      });
    },
    *previous({_}, {put, select}) {
      const {id, sounds}: PlayModelState = yield select(
        ({player}: RootState) => player,
      );
      const index = sounds.findIndex(item => item.id === id);
      const currentIndex = index - 1;
      const currentItem = sounds[currentIndex];
      const previousItem = sounds[currentIndex - 1];
      yield put({
        type: 'setState',
        payload: {
          playState: 'paused',
          id: currentItem.id,
          title: currentItem.title,
          previousId: previousItem?.id || '',
          nextId: id,
          currentTime: 0,
        },
      });
      try {
        yield put({
          type: 'fetchShow',
          payload: {
            id: currentItem.id,
          },
        });
      } catch (error) {
        console.log('播放失败', error);
      }
    },
    *next({_}, {put, select}) {
      const {id, sounds}: PlayModelState = yield select(
        ({player}: RootState) => player,
      );
      const index = sounds.findIndex(item => item.id === id);
      const currentIndex = index + 1;
      const currentItem = sounds[currentIndex];
      const nextItem = sounds[currentIndex + 1];
      yield put({
        type: 'setState',
        payload: {
          playState: 'paused',
          id: currentItem.id,
          title: currentItem.title,
          previousId: id,
          nextId: nextItem?.id || '',
          currentTime: 0,
        },
      });
      yield put({
        type: 'fetchShow',
        payload: {
          id: currentItem.id,
        },
      });
    },
    *setCurrentTime({payload}, {put, select}) {
      const {time} = payload;
      // let res = yield call(sound, time);
      sound.setCurrentTime(time); //修改当前播放时间
      const {id}: PlayModelState = yield select(
        ({player}: RootState) => player,
      );
      yield put({
        type: 'soundsHistory/set',
        payload: {
          data: {
            id,
            currentTime: time,
            duration: getDuration(),
          },
        },
      });
      // console.log(res);
    },
    watcherCurrentTime: [
      function* (sagaEffects) {
        const {call, take, race} = sagaEffects;
        while (true) {
          yield take('play'); //监听某个effects
          yield race([call(currentTime, sagaEffects), take('pause')]); //数组中每一项都应是Promise  只要其中一项被执行 那其他函数将会被退出
        }
      },
      {type: 'watcher'},
    ],
  },
};

export default playerModel;
